#include "../lib_include/CurrentThread.h"

#include <cxxabi.h>
#include <execinfo.h>
#include <stdlib.h>

namespace netlib
{

namespace CurrentThread
{

__thread int t_cachedTid = 0;
__thread char t_tidString[32];
__thread int t_tidStringLength = 6;
__thread const char* t_threadName = "unknown";
static_assert(std::is_same<int, pid_t>::value, "pid_t should be int");

string stackTrace(bool demangle) // 返回函数帧栈
{
    string stack;
    const int max_frames = 200;
    void* frame[max_frames]; // 指针数组，储存函数栈

    // backtrace系统调用，将当前函数的帧栈拷贝到frame指针数组中，max_frames为拷贝上线数量
    // nptrs为实际拷贝的函数地址数量
    int nptrs = ::backtrace(frame, max_frames);

    // backtrace_symbols系统调用，将指针数组中的函数地址转化成函数名称，容易辨识
    // 内核会开辟一段内存用来存储函数名数组，这段需要我们手动释放strings
    char** strings = ::backtrace_symbols(frame, nptrs);

    if (strings)
    {
        size_t len = 256;
        char* demangled = demangle ? static_cast<char*>(::malloc(len)) : nullptr;
        for (int i = 1; i < nptrs; ++i)  // C++编译方式(重载)，要处理函数名字符，使之更具可读性
        {
            if (demangle)
            {
                char* left_par = nullptr;
                char* plus = nullptr;
                for (char* p = strings[i]; *p; ++p)
                {
                    if (*p == '(')
                        left_par = p;
                    else if (*p == '+')
                        plus = p;
                }

                if (left_par && plus)
                {
                    *plus = '\0';
                    int status = 0;
                    char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status);
                    *plus = '+';
                    if (status == 0)
                    {
                        demangled = ret;  // ret could be realloc()
                        stack.append(strings[i], left_par+1);
                        stack.append(demangled);
                        stack.append(plus);
                        stack.push_back('\n');
                        continue;
                    }
                }
            }
            stack.append(strings[i]);
            stack.push_back('\n');
        }
        free(demangled);
        free(strings);
    }
    return stack;
}

} // namespace CurrentThread end

} // namespace netlib end
